/*
 * MIT License
 *
 * Copyright (c) 2023 北京凯特伟业科技有限公司
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package com.je.auth.check;

import com.je.auth.check.exception.BackResultException;
import com.je.auth.check.exception.StopMatchException;
import com.je.auth.check.fun.AuthFunction;
import com.je.auth.check.fun.AuthParamFunction;
import com.je.auth.check.fun.AuthParamRetFunction;
import com.je.auth.check.router.AuthHttpMethod;
import com.je.auth.check.router.AuthPathCheckStaff;
import java.util.List;

/**
 * 路由匹配操作工具类
 *
 * @author kong
 */
public class AuthPathChecker {

    private AuthCheckEngine authCheckEngine;

    public AuthPathChecker(AuthCheckEngine authCheckEngine) {
        this.authCheckEngine = authCheckEngine;
    }

    // -------------------- 路由匹配相关 --------------------

    /**
     * 路由匹配
     *
     * @param pattern 路由匹配符
     * @param path    被匹配的路由
     * @return 是否匹配成功
     */
    public boolean isMatch(String pattern, String path) {
        return authCheckEngine.getAuthTokenContext().matchPath(pattern, path);
    }

    /**
     * 路由匹配
     *
     * @param patterns 路由匹配符集合
     * @param path     被匹配的路由
     * @return 是否匹配成功
     */
    public boolean isMatch(List<String> patterns, String path) {
        if (patterns == null) {
            return false;
        }
        for (String pattern : patterns) {
            if (isMatch(pattern, path)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 路由匹配
     *
     * @param patterns 路由匹配符数组
     * @param path     被匹配的路由
     * @return 是否匹配成功
     */
    public boolean isMatch(String[] patterns, String path) {
        if (patterns == null) {
            return false;
        }
        for (String pattern : patterns) {
            if (isMatch(pattern, path)) {
                return true;
            }
        }
        return false;
    }

    /**
     * Http请求方法匹配
     *
     * @param methods      Http请求方法断言数组
     * @param methodString Http请求方法
     * @return 是否匹配成功
     */
    public boolean isMatch(AuthHttpMethod[] methods, String methodString) {
        if (methods == null) {
            return false;
        }
        for (AuthHttpMethod method : methods) {
            if (method == AuthHttpMethod.ALL || (method != null && method.toString().equalsIgnoreCase(methodString))) {
                return true;
            }
        }
        return false;
    }

    // ------ 使用当前URI匹配

    /**
     * 路由匹配 (使用当前URI)
     *
     * @param pattern 路由匹配符
     * @return 是否匹配成功
     */
    public boolean isMatchCurrURI(String pattern) {
        return isMatch(pattern, authCheckEngine.getAuthTokenContext().getRequest().getRequestPath());
    }

    /**
     * 路由匹配 (使用当前URI)
     *
     * @param patterns 路由匹配符集合
     * @return 是否匹配成功
     */
    public boolean isMatchCurrURI(List<String> patterns) {
        return isMatch(patterns, authCheckEngine.getAuthTokenContext().getRequest().getRequestPath());
    }

    /**
     * 路由匹配 (使用当前URI)
     *
     * @param patterns 路由匹配符数组
     * @return 是否匹配成功
     */
    public boolean isMatchCurrURI(String[] patterns) {
        return isMatch(patterns, authCheckEngine.getAuthTokenContext().getRequest().getRequestPath());
    }

    /**
     * Http请求方法匹配 (使用当前请求方式)
     *
     * @param methods Http请求方法断言数组
     * @return 是否匹配成功
     */
    public boolean isMatchCurrMethod(AuthHttpMethod[] methods) {
        return isMatch(methods, authCheckEngine.getAuthTokenContext().getRequest().getMethod());
    }

    // -------------------- 开始匹配 --------------------

    /**
     * 初始化一个SaRouterStaff，开始匹配
     *
     * @return SaRouterStaff
     */
    public AuthPathCheckStaff newMatch() {
        return new AuthPathCheckStaff(this);
    }

    // ----------------- path匹配

    /**
     * 路由匹配
     *
     * @param patterns 路由匹配符集合
     * @return SaRouterStaff
     */
    public AuthPathCheckStaff match(String... patterns) {
        return newMatch().match(patterns);
    }

    /**
     * 路由匹配排除
     *
     * @param patterns 路由匹配符排除数组
     * @return SaRouterStaff
     */
    public AuthPathCheckStaff notMatch(String... patterns) {
        return newMatch().notMatch(patterns);
    }

    /**
     * 路由匹配
     *
     * @param patterns 路由匹配符集合
     * @return 对象自身
     */
    public AuthPathCheckStaff match(List<String> patterns) {
        return newMatch().match(patterns);
    }

    /**
     * 路由匹配排除
     *
     * @param patterns 路由匹配符排除集合
     * @return 对象自身
     */
    public AuthPathCheckStaff notMatch(List<String> patterns) {
        return newMatch().notMatch(patterns);
    }

    // ----------------- Method匹配

    /**
     * Http请求方式匹配 (Enum)
     *
     * @param methods Http请求方法断言数组
     * @return SaRouterStaff
     */
    public AuthPathCheckStaff match(AuthHttpMethod... methods) {
        return newMatch().match(methods);
    }

    /**
     * Http请求方法匹配排除 (Enum)
     *
     * @param methods Http请求方法断言排除数组
     * @return SaRouterStaff
     */
    public AuthPathCheckStaff notMatch(AuthHttpMethod... methods) {
        return newMatch().notMatch(methods);
    }

    /**
     * Http请求方法匹配 (String)
     *
     * @param methods Http请求方法断言数组
     * @return SaRouterStaff
     */
    public AuthPathCheckStaff matchMethod(String... methods) {
        return newMatch().matchMethod(methods);
    }

    /**
     * Http请求方法匹配排除 (String)
     *
     * @param methods Http请求方法断言排除数组
     * @return SaRouterStaff
     */
    public AuthPathCheckStaff notMatchMethod(String... methods) {
        return newMatch().notMatchMethod(methods);
    }

    // ----------------- 条件匹配

    /**
     * 根据 boolean 值进行匹配
     *
     * @param flag boolean值
     * @return SaRouterStaff
     */
    public AuthPathCheckStaff match(boolean flag) {
        return newMatch().match(flag);
    }

    /**
     * 根据 boolean 值进行匹配排除
     *
     * @param flag boolean值
     * @return SaRouterStaff
     */
    public AuthPathCheckStaff notMatch(boolean flag) {
        return newMatch().notMatch(flag);
    }

    /**
     * 根据自定义方法进行匹配 (lazy)
     *
     * @param fun 自定义方法
     * @return SaRouterStaff
     */
    public AuthPathCheckStaff match(AuthParamRetFunction<Object, Boolean> fun) {
        return newMatch().match(fun);
    }

    /**
     * 根据自定义方法进行匹配排除 (lazy)
     *
     * @param fun 自定义排除方法
     * @return SaRouterStaff
     */
    public AuthPathCheckStaff notMatch(AuthParamRetFunction<Object, Boolean> fun) {
        return newMatch().notMatch(fun);
    }

    // -------------------- 直接指定check函数 --------------------

    /**
     * 路由匹配，如果匹配成功则执行认证函数
     *
     * @param pattern 路由匹配符
     * @param fun     要执行的校验方法
     * @return /
     */
    public AuthPathCheckStaff match(String pattern, AuthFunction fun) {
        return newMatch().match(pattern, fun);
    }

    /**
     * 路由匹配，如果匹配成功则执行认证函数
     *
     * @param pattern 路由匹配符
     * @param fun     要执行的校验方法
     * @return /
     */
    public AuthPathCheckStaff match(String pattern, AuthParamFunction<AuthPathCheckStaff> fun) {
        return newMatch().match(pattern, fun);
    }

    /**
     * 路由匹配 (并指定排除匹配符)，如果匹配成功则执行认证函数
     *
     * @param pattern        路由匹配符
     * @param excludePattern 要排除的路由匹配符
     * @param fun            要执行的方法
     * @return /
     */
    public AuthPathCheckStaff match(String pattern, String excludePattern, AuthFunction fun) {
        return newMatch().match(pattern, excludePattern, fun);
    }

    /**
     * 路由匹配 (并指定排除匹配符)，如果匹配成功则执行认证函数
     *
     * @param pattern        路由匹配符
     * @param excludePattern 要排除的路由匹配符
     * @param fun            要执行的方法
     * @return /
     */
    public AuthPathCheckStaff match(String pattern, String excludePattern, AuthParamFunction<AuthPathCheckStaff> fun) {
        return newMatch().match(pattern, excludePattern, fun);
    }

    // -------------------- 提前退出 --------------------

    /**
     * 停止匹配，跳出函数 (在多个匹配链中一次性跳出Auth函数)
     *
     * @return SaRouterStaff
     */
    public AuthPathCheckStaff stop() {
        throw new StopMatchException();
    }

    /**
     * 停止匹配，结束执行，向前端返回结果
     *
     * @return SaRouterStaff
     */
    public AuthPathCheckStaff back() {
        throw new BackResultException("");
    }

    /**
     * 停止匹配，结束执行，向前端返回结果
     *
     * @param result 要输出的结果
     * @return SaRouterStaff
     */
    public AuthPathCheckStaff back(Object result) {
        throw new BackResultException(result);
    }

}
